Dependency系统对比分析.md•13.5 kB
# ArkTS vs 仓颉:Dependency 系统对比分析
> 目的:分析 ArkTS 的 `Dependency`、`StateToScopes`、`ScopeToStates` 与仓颉的 `Dependency`、`Dependencies` 在功能上的差异,并说明在不修改仓颉现有实现的情况下,需要补充哪些功能。
参考代码:
- ArkTS: `/home/gloria/Cangjie/arkui_ace_engine/frameworks/bridge/arkts_frontend/koala_projects/incremental/runtime/src/states/Dependency.ts`
- 仓颉: `/home/gloria/Cangjie/incremental_runtime/runtime/src/core/Dependency.cj`
---
## 目录
1. [ArkTS 实现的功能](#1-arkts-实现的功能)
- [Dependency 接口](#11-dependency-接口)
- [StateToScopes 类](#12-statetoscopes-类)
- [ScopeToStates 类](#13-scopetostates-类)
- [双向依赖关系](#14-双向依赖关系)
2. [仓颉实现的功能](#2-仓颉实现的功能)
- [Dependency 抽象类](#21-dependency-抽象类)
- [Dependencies 类](#22-dependencies-类)
3. [功能对比与 Gap 分析](#3-功能对比与-gap-分析)
- [架构差异](#31-架构差异)
- [关键功能 Gap](#32-关键功能-gap)
4. [不修改现有实现的情况下,需要补充的功能](#4-不修改现有实现的情况下需要补充的功能)
- [必须补充:条件失效(invalidateIf)](#41-必须补充条件失效invalidateif)
- [可选补充:Scope 侧依赖查询(ScopeToStates 等价物)](#42-可选补充scope-侧依赖查询scopetostates-等价物)
- [可选补充:双向链接辅助类](#43-可选补充双向链接辅助类)
5. [最小补充方案(推荐)](#5-最小补充方案推荐)
6. [完整补充方案(如果允许修改现有实现)](#6-完整补充方案如果允许修改现有实现)
7. [总结](#7-总结)
---
## 1. ArkTS 实现的功能
### 1.1 Dependency 接口
```typescript
export interface Dependency {
readonly states: ScopeToStates | undefined
}
```
**功能**:表示一个可被通知变化的观察者,通过 `states` 属性访问其依赖的状态集合。
**实现者**:`ManagedScope` 实现了 `Dependency` 接口,通过 `states` 属性暴露其依赖的状态。
---
### 1.2 StateToScopes 类
```typescript
export class StateToScopes implements Unique {
private readonly dependencies = new UniqueSet<ScopeToStates>
add(dependency: ScopeToStates): void
remove(dependency: ScopeToStates): void
clear(): undefined
invalidate(): void
invalidateIf(predicate: (element: ScopeToStates) => boolean): void
register(dependency?: Dependency): void
}
```
**功能**:
- **存储**:State → 多个 Scope 的映射(通过 `UniqueSet<ScopeToStates>`)
- **双向链接**:`register()` 时,`this.add(that)` 和 `that.add(this)`,建立双向依赖
- **失效**:`invalidate()` 失效所有依赖的 Scope;`invalidateIf()` 条件失效(用于属性级追踪)
**使用位置**:`StateImpl.dependencies: StateToScopes`,存储依赖该 State 的所有 Scope。
---
### 1.3 ScopeToStates 类
```typescript
export class ScopeToStates implements Unique {
private readonly dependencies = new UniqueMap<StateToScopes, Boolean>
readonly invalidate: () => void
add(dependency: StateToScopes): void
remove(dependency: StateToScopes): void
clear(): undefined
reset(): void // 清理未使用的依赖
}
```
**功能**:
- **存储**:Scope → 多个 State 的映射(通过 `UniqueMap<StateToScopes, Boolean>`)
- **失效回调**:构造时传入 `invalidate()` 回调,指向 Scope 的失效方法
- **清理**:`reset()` 清理未使用的依赖(基于 marker 机制)
**使用位置**:`ScopeImpl._states: ScopeToStates`,存储该 Scope 依赖的所有 State。
---
### 1.4 双向依赖关系
```
State.dependencies (StateToScopes)
↓ 包含多个
ScopeToStates (在各个Scope._states中)
↓ 包含多个
State.dependencies (回到StateToScopes)
```
**建立流程**:
```typescript
// StateImpl.onAccess()
onAccess(propertyName?: string): void {
const dependency = this.manager?.dependency // 获取当前Scope
this.dependencies?.register(dependency) // 双向注册
}
// StateToScopes.register()
register(dependency?: Dependency): void {
const that = dependency?.states // 获取ScopeToStates
if (that) {
this.add(that) // State记录Scope
that.add(this) // Scope记录State
}
}
```
---
## 2. 仓颉实现的功能
### 2.1 Dependency 抽象类
```cj
public abstract class Dependency <: UniqueObject & Equatable<Dependency> {
public func invalidate(): Unit
}
```
**功能**:表示一个可被通知失效的观察者,通过 `invalidate()` 方法被通知失效。
**实现者**:`ManagedScope` 实现了 `Dependency`,通过 `invalidate()` 方法实现失效传播。
---
### 2.2 Dependencies 类
```cj
public class Dependencies {
private var dependencies = None<HashSet<Dependency>>
private var latest = None<Dependency>
func register(dependency: ?Dependency): Unit
public func onUpdate(invalidate: Bool): Unit
}
```
**功能**:
- **存储**:存储 `HashSet<Dependency>`(即 Scope 集合),或单个 `latest`
- **注册**:`register()` 将 Dependency(即 Scope)添加到集合
- **更新**:`onUpdate(invalidate)` 根据 `invalidate` 标志决定是否失效所有依赖
**使用位置**:
- `StateImpl.dependencies: ?Dependencies`,存储依赖该 State 的所有 Scope
- `ParameterImpl.dependencies: ?Dependencies`,存储依赖该参数的所有 Scope
- `ScopeImpl.dependencies: ?Dependencies`,存储该 Scope 依赖的其他 Dependency
---
## 3. 功能对比与 Gap 分析
### 3.1 架构差异
| 特性 | ArkTS | 仓颉 |
|------|-------|------|
| **依赖方向** | 双向链接(State ↔ Scope) | 单向集合(State → Scope) |
| **存储结构** | `StateToScopes` ↔ `ScopeToStates` | `Dependencies`(仅存储 Scope) |
| **双向注册** | `register()` 自动双向链接 | 仅单向注册(State → Scope) |
| **Scope 侧依赖** | `Scope._states: ScopeToStates` | `Scope.dependencies: ?Dependencies`(存储其他 Dependency) |
---
### 3.2 关键功能 Gap
#### Gap 1: 双向链接缺失
**ArkTS**:
- `StateToScopes.register()` 会同时调用 `this.add(that)` 和 `that.add(this)`
- Scope 通过 `_states: ScopeToStates` 可以查询自己依赖了哪些 State
**仓颉**:
- `Dependencies.register()` 只做单向注册(State → Scope)
- Scope 没有直接查询"依赖了哪些 State"的能力
**影响**:
- Scope 无法主动清理不再使用的依赖(ArkTS 的 `ScopeToStates.reset()`)
- 无法实现"从 Scope 出发查询依赖"的功能
---
#### Gap 2: 条件失效(invalidateIf)缺失
**ArkTS**:
```typescript
StateToScopes.invalidateIf(predicate: (element: ScopeToStates) => boolean): void {
this.dependencies.forEach((dependency: ScopeToStates) => {
if (predicate(dependency)) dependency.invalidate()
})
}
```
**仓颉**:
- `Dependencies.onUpdate()` 只有 `invalidate: Bool` 标志,无法条件失效
**影响**:
- **无法实现属性级失效**:当对象属性修改时,无法只失效访问了该属性的 Scope
- 必须整体失效,导致过度失效
**使用场景**(ArkTS):
```typescript
// StateImpl.updateStateSnapshot()
if (modifiedTrackedScopes) {
dependencies.invalidateIf((dependency: ScopeToStates): boolean => {
return modifiedTrackedScopes?.has(dependency) == true
})
} else {
dependencies.invalidate()
}
```
---
#### Gap 3: Scope 侧依赖查询缺失
**ArkTS**:
- `Scope._states: ScopeToStates` 可以查询 Scope 依赖了哪些 State
- `ScopeToStates.reset()` 可以清理未使用的依赖
**仓颉**:
- `Scope.dependencies: ?Dependencies` 存储的是其他 Dependency(如子 Scope),不是依赖的 State
- 无法查询 Scope 依赖了哪些 State
**影响**:
- 无法实现依赖清理(reset)机制
- 无法实现"从 Scope 出发查询依赖"的功能
---
#### Gap 4: 依赖清理机制缺失
**ArkTS**:
```typescript
ScopeToStates.reset(): void {
const current = this.marker
this.marker = !current
this.dependencies.deleteIf((dependency: StateToScopes, marker: Boolean) => {
if (current == marker) return false
dependency.remove(this)
return true
})
}
```
**仓颉**:
- `Dependencies` 没有 `reset()` 机制
- 依赖一旦注册,除非 Scope 销毁,否则不会自动清理
**影响**:
- 依赖可能累积,无法及时清理不再使用的依赖
- 可能导致内存泄漏或性能问题
---
## 4. 不修改现有实现的情况下,需要补充的功能
### 4.1 必须补充:条件失效(invalidateIf)
**位置**:在 `Dependencies` 类中添加
**实现**:
```cj
public func invalidateIf(predicate: (Dependency) -> Bool): Unit {
if (let Some(dependencies) <- this.dependencies) {
for (dependency in dependencies) {
if (predicate(dependency)) {
dependency.invalidate()
}
}
} else if (let Some(latest) <- this.latest) {
if (predicate(latest)) {
latest.invalidate()
}
}
}
```
**用途**:
- 支持属性级失效(结合 `TrackedScopes`)
- 支持细粒度失效控制
**影响**:这是实现属性级更新的**关键前提**。
---
### 4.2 可选补充:Scope 侧依赖查询(ScopeToStates 等价物)
**位置**:在 `ManagedScope` 或 `ScopeImpl` 中添加新字段
**实现**:
```cj
// 在 ManagedScope 中添加
private var states = None<ScopeStates>
class ScopeStates {
private var dependencies = None<HashSet<StateToScopes>>
func add(state: StateToScopes): Unit
func remove(state: StateToScopes): Unit
func reset(): Unit // 清理未使用的依赖
}
```
**注意**:这需要修改 `ManagedScope` 结构,可能与"不修改现有实现"冲突。
**替代方案**:通过 `Dependencies` 的扩展方法实现,不修改 `ManagedScope`。
---
### 4.3 可选补充:双向链接辅助类
**位置**:新增 `StateToScopes` 和 `ScopeToStates` 等价类
**实现**:
```cj
// 新增 StateToScopes 类
public class StateToScopes {
private var dependencies = None<HashSet<ScopeStates>>
func register(dependency: ?Dependency): Unit {
// 双向注册逻辑
}
func invalidateIf(predicate: (ScopeStates) -> Bool): Unit {
// 条件失效
}
}
// 新增 ScopeToStates 类
public class ScopeToStates {
private var dependencies = None<HashSet<StateToScopes>>
let invalidate: () -> Unit
func add(state: StateToScopes): Unit
func reset(): Unit
}
```
**注意**:这需要修改 `StateImpl` 和 `ScopeImpl` 的字段类型,可能与"不修改现有实现"冲突。
---
## 5. 最小补充方案(推荐)
### 方案:仅补充 `invalidateIf` 方法
**理由**:
1. **最小改动**:只需在 `Dependencies` 类中添加一个方法
2. **关键功能**:这是实现属性级失效的**唯一前提**
3. **向后兼容**:不影响现有代码
**实现**:
```cj
// 在 Dependencies 类中添加
public func invalidateIf(predicate: (Dependency) -> Bool): Unit {
if (let Some(dependencies) <- this.dependencies) {
for (dependency in dependencies) {
if (predicate(dependency)) {
dependency.invalidate()
}
}
} else if (let Some(latest) <- this.latest) {
if (predicate(latest)) {
latest.invalidate()
}
}
}
```
**使用场景**:
- 在 `StateImpl.updateStateSnapshot()` 中,结合 `TrackedScopes` 实现属性级失效
- 在 `Dependencies.onUpdate()` 中,当需要条件失效时调用
---
## 6. 完整补充方案(如果允许修改现有实现)
如果需要完整实现 ArkTS 的功能,需要:
1. **修改 `StateImpl`**:
- 将 `dependencies: ?Dependencies` 改为 `dependencies: ?StateToScopes`
- `StateToScopes` 类实现双向链接
2. **修改 `ScopeImpl`**:
- 添加 `_states: ?ScopeToStates` 字段
- `ScopeToStates` 类存储 Scope 依赖的 State
3. **修改注册逻辑**:
- `StateToScopes.register()` 实现双向注册
- `ScopeToStates.add()` 实现双向添加
4. **添加清理机制**:
- `ScopeToStates.reset()` 清理未使用的依赖
---
## 7. 总结
### 功能对比表
| 功能 | ArkTS | 仓颉 | Gap |
|------|-------|------|-----|
| **双向链接** | ✅ State ↔ Scope | ❌ 仅 State → Scope | 有 |
| **条件失效** | ✅ `invalidateIf()` | ❌ 缺失 | 有 |
| **Scope 侧查询** | ✅ `Scope._states` | ❌ 缺失 | 有 |
| **依赖清理** | ✅ `reset()` | ❌ 缺失 | 有 |
| **基础失效** | ✅ `invalidate()` | ✅ `onUpdate(true)` | 无 |
### 最小补充建议
**必须补充**:`Dependencies.invalidateIf()` 方法
- 理由:实现属性级失效的**关键前提**
- 影响:支持细粒度失效,避免过度失效
- 改动:最小,仅添加一个方法
**可选补充**:Scope 侧依赖查询(如果允许修改 `ManagedScope`)
- 理由:实现依赖清理和从 Scope 出发的查询
- 影响:提升依赖管理能力,避免依赖累积
- 改动:需要修改 `ManagedScope` 结构
---
**关键结论**:
- 仓颉的 `Dependencies` 类已经实现了基础依赖管理功能
- **主要缺失**是 `invalidateIf()` 方法,这是实现属性级更新的**关键前提**
- 双向链接和依赖清理是可选的增强功能,但 `invalidateIf()` 是必须的